/*
 * block_matrix.h
 *
 *  Created on: Nov 18, 2011
 *      Author: bendischinger
 */

#ifndef BLOCK_MATRIX_H_
#define BLOCK_MATRIX_H_

#include "block_cache.h"

typedef struct block_matrix {
	int fd;
	int flags;
	int blk_rows; /* number of rows of blocks */
	int blk_cols; /* number of columns of blocks */
	int blk_size; /* total size of each block in bytes */
	int elem_rows; /* number of (int) element rows in block */
	int elem_cols; /* number of (int) element columns in block */
	blk_cache_t blk_cache; /* optional block cache */
	int blk_cache_size;
} block_matrix_t;

typedef struct block_matrix_ij {
	int blk_i;
	int blk_j;
	int elem_i;
	int elem_j;
} block_matrix_ij_t;

#define MATRIX_HEADER 4096
#define	BLOCK_FD_OFFSET(mat, row, col) ((row * mat->blk_cols + col) * mat->blk_size + MATRIX_HEADER)

#define M_CREATE 	0x00000001
#define M_BLK_CACHE	0x00000002
#define M_AIO		0x00000004
#define M_DIRECT_IO	0x00000008
#define M_PREFETCH	0x00000010

/* Index into individual block */
#define BLOCK_IDX(mat, blk_i, blk_j) (blk_i*mat->blk_cols + blk_j)

#define BLOCK_MATRIX_ELEM(mat, row, col, blk_i, blk_j) \
	((row*mat->blk_cols+col)*mat->elem_cols*mat->elem_rows + \
	 blk_i*mat->elem_cols + blk_j)

void init_block_matrix(block_matrix_t *mat, int blk_rows, int blk_cols, int elem_rows, int elem_cols);
int open_block_matrix(char *filename, block_matrix_t *mat, int flags, int cache_size);
void close_block_matrix(block_matrix_t *);

void write_block(block_matrix_t *mat, int *block, int i, int j);
void read_block(block_matrix_t *mat, int *block, int i, int j);

void add_matrix(block_matrix_t *left, block_matrix_t *right, block_matrix_t *out);
void multiply_matrix(block_matrix_t *left, block_matrix_t *right, block_matrix_t *out);
void transpose_matrix(block_matrix_t *mat, block_matrix_t *out);
void search_matrix(block_matrix_t *mat, int item, block_matrix_ij_t *result);

void print_matrix(block_matrix_t *mat);
void print_matrix_header(block_matrix_t *mat);

void populate_ordered_matrix(block_matrix_t *mat);
void populate_identity_matrix(block_matrix_t *mat);
void populate_random_matrix(block_matrix_t *mat);

void add_block(block_matrix_t *mat, int *left, int *right, int *out);
void multiply_block(block_matrix_t *mat, int *left, int *right, int *out);
void transpose_block(block_matrix_t *mat, int *in, int *out);
int search_block(block_matrix_t *mat, int *in, int item);

#endif /* BLOCK_MATRIX_H_ */
